package com.zyh.em.evaluate;

import com.zyh.em.entity.EvaluateData;
import com.zyh.em.entity.EvaluateReport;
import com.zyh.em.entity.GeoPoint;
import com.zyh.em.entity.HistoryData;

/**
 * 速度评估
 */
public class SpeedEvaluate  extends AbstractEvaluate{
    private double speedShreshold;//速度阈值：单位是：km/h

    public SpeedEvaluate(double speedShreshold) {
        this.speedShreshold = speedShreshold;
    }

    @Override
    public void evaluate(EvaluateData evaluateData, HistoryData historyData, EvaluateReport evaluateReport, EvaluateChain evaluateChain) {
		

        long time = evaluateData.getTime();
        long lastLoginTime = historyData.getLastLoginTime();

        GeoPoint geoPoint = evaluateData.getGeoPoint();
        GeoPoint lastLoginGeoPoint = historyData.getLastLoginGeoPoint();

        if(lastLoginGeoPoint == null){//如果之前没有登录，则没有风险
            evaluateReport.setRiskFactor("speed",false);
        }else {
            //调用自己定义的方法，完成是否有风险的评估
            boolean isRisk = doEval(time,lastLoginTime,geoPoint,lastLoginGeoPoint);
            evaluateReport.setRiskFactor("speed",isRisk);
        }

        //
        evaluateChain.doEvaluate(evaluateData, historyData, evaluateReport);
    }

    /**
     * 用来做风险评估的
     * @param time 评估的时间
     * @param lastLoginTime 最后一次成功登录时间
     这里是埋伏
     * @param geoPoint 评估的地理位置
     * @param lastLoginGeoPoint 最后一次成功登录的地理位置
     * @return 是否有风险
     */
    private boolean doEval(long time, long lastLoginTime, GeoPoint geoPoint, GeoPoint lastLoginGeoPoint) {

        long t = time - lastLoginTime;//时间的单位是毫秒
		if(t <= 0){//评估日志晚于登录日志则直接返回false
            return false;
        }
        if(geoPoint.equals(lastLoginGeoPoint)){
            return false;
        }
        //把毫秒为单位的时间t转换成小时为单位的
        double timeForSpedd = t / 1000.0 / 60 / 60;
		
        //计算球面距离:单位km
        double d=calcDistance(geoPoint,lastLoginGeoPoint);

        //计算速度
        double speed=d/timeForSpedd;

        return speed>speedShreshold;
    }

    /**
     * 根据球面距离公式计算球面距离的
     * @param geoPoint 地理位置
     * @param lastLoginGeoPoint 地理位置
     * @return 两点之间的球面距离
     */
    private static double calcDistance(GeoPoint geoPoint, GeoPoint lastLoginGeoPoint) {
        /**
         * 1.球面距离公式：
         * 设所求点A ，纬度角β1 ，经度角α1 ；点B ，纬度角β2 ，经度角α2。
         * 则距离S=R·arc cos[cosβ1cosβ2cos（α1-α2）+sinβ1sinβ2]
         * ，其中R为球体半径
         *
         * 在这个公式中，α、β是以弧度为单位的。
         *
         * 在地理位置，经纬度是角度为单位的。所以在计算的时候，需要把角度转换为弧度
         */

        double a1=Math.toRadians(geoPoint.getLongitude());//A点经度，转换成弧度单位
        double b1=Math.toRadians(geoPoint.getLatitude());//A点纬度，转换成弧度单位

        double a2=Math.toRadians(lastLoginGeoPoint.getLongitude());//B点经度，转换成弧度单位
        double b2=Math.toRadians(lastLoginGeoPoint.getLatitude());//B点纬度，转换成弧度单位

        final double r=6378.137;//地球平均半径

        return r*Math.acos(Math.cos(b1)*Math.cos(b2)*Math.cos(a1-a2)+Math.sin(b1)*Math.sin(b2));  
    }

  
}